package com.css.openapi.config;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FastByteArrayOutputStream;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.css.common.core.exception.ServiceException;
import com.css.common.core.session.SessionUtils;
import com.css.openapi.entity.Ptjr;
import com.css.openapi.service.JrptglService;
import feign.FeignException;
import feign.RequestTemplate;
import feign.Response;
import feign.codec.Decoder;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;

import javax.annotation.Resource;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * @description:
 * @Title: YljyConfig
 * @Author xlw
 * @Package com.invoice.tcc.feign.yljy.config
 * @Date 2025/9/11 15:20
 */
@Slf4j
public class YljyConfig {

    // 从配置文件读取appId
    @Value("${yljy.app-id}")
    private String appId;

    // 从配置文件读取appKey（签名密钥）
    @Value("${yljy.app-key}")
    private String appKey;

    @Value("${yljy.sm4-key}")
    private String sm4Key;

    @Value("${yljy.plat-id}")
    private String platId;

    @Resource
    private JrptglService jrptglService;

    @Bean
    public Encoder encoder() {
        return new Encoder() {
            @Override
            public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
                try {
                    //时间戳
                    String timestamp = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
                    //随机数
                    String nonce = IdUtil.simpleUUID();
                    //版本
                    String msgVer = "0.2";
                    //获取参数
                    String aId = appId;
                    String aKey = appKey;
                    String pId = platId;
                    String sK = sm4Key;
//                    Ptjr ptjr = jrptglService.queryJrptByAppid(SessionUtils.getAppid());
//                    if (Objects.nonNull(ptjr)) {
//                        aId = ptjr.getGsuuid();
//                        aKey = ptjr.getAppkey();
//                        pId = ptjr.getPlatId();
//                        sK = ptjr.getEncrypKey();
//                    }
                    SM4AccessTools sm4 = new SM4AccessTools(sK);
                    Map<String, Object> bean = BeanUtil.beanToMap(object, false, true);
                    bean.put("platId", pId);
                    JSONConfig config = new JSONConfig();
                    config.setIgnoreNullValue(true);
                    config.setDateFormat(DatePattern.NORM_DATETIME_PATTERN);
                    String body = JSONUtil.toJsonStr(bean, config);
                    log.info("银联第三方能力请求数据:{}", body);
                    //签名
                    String signature = getAuthorization(aId, aKey, timestamp, nonce, body);
                    log.info("银联第三方能力请求签名:{}", signature);
                    //设置请求头
                    template.header("Content-Type", "application/json; charset=UTF-8");
                    template.header("appId", aId);
                    template.header("nonce", nonce);
                    template.header("timestamp", timestamp);
                    template.header("msgVer", msgVer);
                    template.header("signature", signature);
                    //设置请求体
                    String encrypt = sm4.encByCustom(body);
                    log.info("银联第三方能力请求数据加密:{}", encrypt);
                    template.body(encrypt);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        };
    }

    /**
     * 译码器
     *
     * @return {@link Decoder }
     */
    @Bean
    public Decoder decoder() {
        return new Decoder() {
            @Override
            public Object decode(Response response, Type type) throws FeignException {
                try (FastByteArrayOutputStream read = IoUtil.read(response.body().asInputStream(), true)) {
                    //获取参数
                    String aId = appId;
                    String aKey = appKey;
                    String sK = sm4Key;
//                    Ptjr ptjr = jrptglService.queryJrptByAppid(SessionUtils.getAppid());
//                    if (Objects.nonNull(ptjr)) {
//                        aId = ptjr.getGsuuid();
//                        aKey = ptjr.getAppkey();
//                        sK = ptjr.getEncrypKey();
//                    }
                    SM4AccessTools sm4 = new SM4AccessTools(sK);
                    String data = read.toString(CharsetUtil.UTF_8);
                    log.info("银联第三方能力响应数据:{}", data);
                    String decrypt = sm4.decByCustom(data);
                    log.info("银联第三方能力响应数据解析:{}", decrypt);
                    String timestamp = response.headers().get("timestamp").stream().findFirst().orElseThrow(() -> new ServiceException("timestamp not found"));
                    String nonce = response.headers().get("nonce").stream().findFirst().orElseThrow(() -> new ServiceException("nonce not found"));
                    String signature = response.headers().get("signature").stream().findFirst().orElseThrow(() -> new ServiceException("signature not found"));
                    String signature1 = getAuthorization(aId, aKey, timestamp, nonce, decrypt);
                    if (!signature.equals(signature1)) {
                        throw new ServiceException("签名验证失败");
                    }
                    return JSON.parseObject(decrypt, type);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        };
    }

    private String getAuthorization(String appid, String appkey, String timestamp, String nonce, String body)
            throws Exception {
        byte[] data = body.getBytes(StandardCharsets.UTF_8);
        InputStream is = new ByteArrayInputStream(data);
        String testSH = DigestUtils.sha256Hex(is);
        String s1 = appid + timestamp + nonce + testSH;
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(appkey.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
        byte[] localSignature = mac.doFinal(s1.getBytes(StandardCharsets.UTF_8));
        return Base64.encodeBase64String(localSignature);
    }

}
